/*
 * 文件名： ScanPayBankResBase.java
 * 
 * 工程名称: bis-web
 *
 * Gopay
 *
 * 创建日期： 2016年8月5日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.web.controller.scan;

import java.util.Enumeration;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.bis.common.util.IpAddrUtil;
import com.gopay.bis.common.util.SendSmsUtils;
import com.gopay.bis.domain.order.OrderInfo;
import com.gopay.common.Result;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.proccode.ProcCodeInfo;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.RSAEncoderUtil;
import com.gopay.remote.bank.ScanPayInteractRemoteService;

/**
 * 扫码支付异步返回基类
 *
 * @author 宣广海
 *
 * @version 
 *
 * @since 2016年8月5日
 */
public abstract class ScanPayBankResBase {
	
	/**
	 * 定义日志对象
	 */
	private static Log logger = LogFactory.getLog(ScanPayBankResBase.class);
	
	@Resource(name = "bisConfig")
	protected Map<String, String> bisConfig;

	@Resource(name = "scanPayInteractService")
	private ScanPayInteractRemoteService scanPayInteractService;

//	@Resource(name = "bisInteractExternalService")
//	BankInteractRemoteService bisInteractExternalService;
	
	@Resource(name = "dicProcCodeService")
	private DicProcCodeService dicProcCodeService;

	@Resource(name = "notifyCashier")
	private HttpTransport notifyCashier;

	@Resource(name = "cashierBgNotifyRemoteService")
	private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;
	
//	@Resource(name = "bankOrderService")
//	private BankOrderService bankOrderService;
	
	@Resource(name = "smsConfig")
    private Map<String, String> smsConfig;
	
	/**
	 * 构建支付类对象
	 * 
	 * @param orderId
	 * @return
	 */
	protected abstract BaseMessage buildMessage(HttpServletRequest request);

	/**
	 * 构建返回收银台参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract OrderInfo buildOrderInfo(HttpServletRequest request,Result result);

	/**
	 * 验证返回参数
	 * 
	 * @param request
	 * @return
	 */
	protected abstract boolean checkParameters(HttpServletRequest request);
	/**
	 * 
	 * 功能描述：通知银行接口
	 *
	 * @param response
	 * @param orderInfo
	 * @return
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年8月9日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	protected abstract boolean notifyBank(HttpServletResponse response,OrderInfo orderInfo);
	
	/**
	 * 通知入口
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	protected void execute(HttpServletRequest request,HttpServletResponse response) {
		/**
		 * 打印请求参数
		 */
		this.displayRequestParameters(request, logger);
		/**
		 * 校验参数
		 */
		boolean isCheck = checkParameters(request);
//		/**
//		 * 前台通知地址
//		 */
//		String notifyUrl = bisConfig.get("BIS.CLIENT.NOTIFY.CASHIER.BANK.RES");
//		String viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD.FAIL");
//		ModelAndView model = new ModelAndView();
//		model.setViewName(viewName);
		try {
			/**
			 * 校验参数通过
			 */
			if(isCheck){
				OrderInfo orderInfo = null;
				/**
				 * 异步通知验签
				 */
				Result result = scanPayInteractService.verify(buildMessage(request));
				/**
				 *  构建发往收银台的参数
				 */
				orderInfo = buildOrderInfo(request, result);
				
				orderInfo.setSign(sign(orderInfo));//  前台通知cashier签名数据
				
				logger.error(orderInfo.getOrderId() + " Referer: " + request.getHeader("Referer") + " Ip: " + IpAddrUtil.getRemoteRealIpAddr(request));
				
				if (result.isSuccess()) {
					if ((Boolean) result.getDefaultModel()) {
						
						Map<String, String> param  = (Map<String, String>)result.getModel("isNotifyCashier");
						
						param.put("sign", signRes(param));// 后台通知cashier签名数据
						
						logger.error("notify cashier param:"+param);
//						String gopayOrderID = param.get("orderId");
//						List bankOrderList = bankOrderService.getBankOrdersByGopayOrderId(gopayOrderID);
//						 BankOrder bankOrder =null;
//						 if(bankOrderList!=null && bankOrderList.size()>0){
//							 bankOrder = (BankOrder)bankOrderList.get(0);
//						 }
						//根据订单号判断如果为外部平台的话走外部平台返回签名流程
//						if(BisPayCheckUtils.checkExternalOrderID(gopayOrderID)){
//							BisExternalMessage bisMessage = new BisExternalMessage();
//							bisMessage.setOrderId(gopayOrderID);
//							bisMessage.setAmount(new BigDecimal(param.get("amt")));
//							bisMessage.setBank(bankOrder.getBankCode());
//							if(param.get("payStatus").equals("00")){
//								bisMessage.setTradeState("1");
//							}else{
//								bisMessage.setTradeState("-1");
//							}
//							Result bisResult  = bisInteractExternalService.bankBack(bisMessage);
//							//如果银行返回成功并且签名成功设置成功页面
//							if(param.get("payStatus").equals("00") && bisResult.isSuccess()){
//								String redirectUrl = (String)bisResult.getModel("redirectUrl");
//								viewName = "redirect:"+redirectUrl;
//							}
//							model.setViewName(viewName);
//							logger.error("外部平台订单["+gopayOrderID+"]处理成功，跳转地址： "+viewName);
//							logger.error(param);
//							return model;
//					}else{
							/**
							 * 通知cashier入账
							 */
							String isFront = param.get("isFront");
							if("false".equals(isFront)){
								/*notifyCashier.submit(param);*/ //生产优化10期 lx 2017-9-30 16:23:37
								cashierBgNotifyRemoteService.callBgNotify(param);
							}							
							// 设置成功页面
							//viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
							// 通知银行
							if (orderInfo.getIsNotify()) {
								notifyBank(response, orderInfo);
							}							
//						}
					} else if (!(Boolean) result.getDefaultModel()) {
						/**
						 *  验签失败,不操作数据库也不通知cashier
						 */
						ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(ProcCodeConstants.PROC_CODE_100E6040);
						orderInfo.setRetCode(ProcCodeConstants.PROC_CODE_100E6079);
						orderInfo.setRetMsg(procCodeInfo.getMessage());
						logger.error("平台订单["+orderInfo.getOrderId()+"]验签失败!");
					}
					// TODO 执行不到下面流程
					else if (StringUtils.equals(ProcCodeConstants.PROC_CODE_100E6026,result.getResultCode())) {
						// 重复验签也返回成功页面，由收银台统一跳转
						//viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
						// 通知银行
						if (orderInfo.getIsNotify()) {
							notifyBank(response, orderInfo);
						}
					}
				} else {
					/**
					 *  验签异常,不操作数据库也不通知cashier
					 */
					ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(result.getResultCode());
					orderInfo.setRetCode(result.getResultCode());
					orderInfo.setRetMsg(procCodeInfo.getMessage());
					if(StringUtils.equals(result.getResultCode(), ProcCodeConstants.PROC_CODE_100E5079)){
                        SendSmsUtils.sendSmsErr(smsConfig.get("switch"), smsConfig.get("mobile"),"注意!!!订单金额不一致,银行:"+orderInfo.getBankName()+"orderId:"+orderInfo.getOrderId());
                    }
				}
//				model.setViewName(viewName);
//				model.addObject("notifyUrl", notifyUrl);
//				model.addObject("orderInfo", orderInfo);
//				model.addObject("errorCode", orderInfo.getRetCode());
//				model.addObject("errorMsg", orderInfo.getRetMsg());
//				logger.error(orderInfo);
//				logger.error(notifyUrl);
				//logger.error("平台订单["+orderInfo.getOrderId()+"]处理成功，跳转地址： "+viewName);
			}else{
//				model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100E7023);
//				model.addObject("errorMsg", "bank back notify parameters is null");
				logger.error("bank back notify parameters is null");
			}
		} catch (Exception e) {
			logger.error("BankResBase error：", e);
//			model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100F1002);
//			model.addObject("errorMsg", e.getMessage());
		}
	}
	/**
	 * 
	 * 功能描述：输出异步通知请求参数，威富通支付返回的request获取输入流，然后输出通知参数
	 *
	 * @param request
	 * @param logger
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年8月9日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	@SuppressWarnings("rawtypes")
	protected void displayRequestParameters(HttpServletRequest request,Log logger) {
		for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) {
			String eleName = (String) enumeration.nextElement();
			String eleValue = request.getParameter(eleName);
			if (logger != null) {
				logger.error("map key: [" + eleName + "]，value: [" + eleValue+ "]");
			}
		}
	}
	public String sign(OrderInfo orderInfo) {
        StringBuffer sign = new StringBuffer();
        String orderId = orderInfo.getOrderId();
        String amt = orderInfo.getAmt();
        String retCode = orderInfo.getRetCode();
        String retMsg = orderInfo.getRetMsg();
        String payStatus = orderInfo.getPayStatus();
        String notifyNum = orderInfo.getNotifyNum();
        String cardType = orderInfo.getCardType();
        sign.append(orderId).append("|");
        sign.append(amt).append("|");
        sign.append(retCode).append("|");
        sign.append(retMsg).append("|");
        sign.append(payStatus).append("|");
        sign.append(notifyNum).append("|");
        sign.append(cardType);
        try {
            return RSAEncoderUtil.sign(sign.toString());
        } catch (Exception e) {
            logger.error("bis通知cashier OrderInfo签名异常", e);
        }
        return "";
    }
	 public String signRes(Map res) {
	        StringBuffer sign = new StringBuffer();
	        String orderId = (String)res.get("orderId");
	        String amt = (String)res.get("amt");
	        String retCode = (String)res.get("retCode");
	        String retMsg = (String)res.get("retMsg");
	        String payStatus = (String)res.get("payStatus");
	        String notifyNum = (String)res.get("notifyNum");
	        String cardType = (String)res.get("cardType");
	        sign.append(orderId).append("|");
	        sign.append(amt).append("|");
	        sign.append(retCode).append("|");
	        sign.append(retMsg).append("|");
	        sign.append(payStatus).append("|");
	        sign.append(notifyNum).append("|");
	        sign.append(cardType);
	        try {
	            return RSAEncoderUtil.sign(sign.toString());
	        } catch (Exception e) {
	            logger.error("bis通知cashier Map签名异常", e);
	        }
	        return "";
	    }
}
